﻿//
// DotNetNuke® - http://www.dotnetnuke.com
// Copyright (c) 2002-2012
// by DotNetNuke Corporation
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 
// documentation files (the "Software"), to deal in the Software without restriction, including without limitation 
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and 
// to permit persons to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or substantial portions 
// of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 
// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 
// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
// DEALINGS IN THE SOFTWARE.
//

using System;
using System.Collections.Generic;
using DotNetNuke.Common.Utilities;
using DotNetNuke.Modules.Contest.Components.Entities;
using DotNetNuke.Modules.Contest.Components.Integration;
using DotNetNuke.Modules.Contest.Providers.Data;
using DotNetNuke.Modules.Contest.Providers.Data.SqlDataProvider;

namespace DotNetNuke.Modules.Contest.Components.Controllers
{
	public class ContestController
	{

		private readonly IDataProvider _dataProvider;

		#region Constructors

		/// <summary>
		/// 
		/// </summary>
		public ContestController() {
			_dataProvider = ComponentModel.ComponentFactory.GetComponent<IDataProvider>();
			if (_dataProvider != null) return;

			// get the provider configuration based on the type
			var defaultprovider = Data.DataProvider.Instance().DefaultProviderName;
			const string dataProviderNamespace = "DotNetNuke.Modules.Contest.Providers.Data";

			if (defaultprovider == "SqlDataProvider") {
				_dataProvider = new SqlDataProvider();
			} else {
				var providerType = dataProviderNamespace + "." + defaultprovider;
				_dataProvider = (IDataProvider)Framework.Reflection.CreateObject(providerType, providerType, true);
			}

			ComponentModel.ComponentFactory.RegisterComponentInstance<IDataProvider>(_dataProvider);
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="dataProvider"></param>
		public ContestController(IDataProvider dataProvider)
		{
			//DotNetNuke.Common.Requires.NotNull("dataProvider", dataProvider);
			_dataProvider = dataProvider;
		}

		#endregion

		#region Public Methods

		/// <summary>
		/// Returns a collection of contest entries for management (ie. multiple rows of data).
		/// </summary>
		/// <param name="ModuleId"></param>
		/// <returns></returns>
		public List<EntryInfo> GetAllEntries(int moduleid)
		{
			return CBO.FillCollection<EntryInfo>(_dataProvider.GetAllEntries(moduleid));
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="ModuleId"></param>
		/// <returns></returns>
		public List<EntryInfo> GetActiveCachedEntries(int moduleid)
		{

			var colEntries = new List<EntryInfo>();
			var strCacheKey = "Contest-Cache" + "-" + moduleid;
			colEntries = (List<EntryInfo>)DataCache.GetCache(strCacheKey);

			if (colEntries == null)
			{
				// caching settings
				Int32 timeOut = 20 * Convert.ToInt32(DotNetNuke.Entities.Host.Host.PerformanceSetting);

				colEntries = GetActiveEntries(moduleid);

				//Cache Forum if timeout > 0 and Forum is not null
				if (timeOut > 0 & colEntries != null)
				{
					DataCache.SetCache(strCacheKey, colEntries, TimeSpan.FromMinutes(timeOut));
				}
			}
			return colEntries;
		}

		/// <summary>
		/// returns a single Contest Entry (equivalent to a single row of data)
		/// </summary>
		/// <param name="contestEntryId"></param>
		/// <returns></returns>
		public EntryInfo GetEntry(int contestEntryId)
		{
			return (EntryInfo)CBO.FillObject(_dataProvider.GetEntry(contestEntryId), typeof(EntryInfo));
		}

		/// <summary>
		/// Adds an entry to the data store and returns the primary key that was generated for the new entry that was just added.
		/// </summary>
		/// <param name="objEntry"></param>
		/// <returns></returns>
		public EntryInfo AddEntry(EntryInfo objEntry, int tabId)
		{
			objEntry.ContestEntryId = _dataProvider.AddEntry(objEntry.EntryName, objEntry.Description, objEntry.AuthorName, objEntry.SortOrder, objEntry.Active, objEntry.PermitVoting, objEntry.SmallImageUrl, objEntry.LargeImageUrl, objEntry.DemoUrl, objEntry.DownloadUrl, objEntry.ModuleId, objEntry.CreatedByUserId, objEntry.EnableDownload, objEntry.AuthorUrl, objEntry.Category);


			objEntry.ContentItemId = CompleteEntryCreation(objEntry, tabId);

		    return objEntry;
		}

		/// <summary>
		/// Updates an existing entry  in the data store.
		/// </summary>
		/// <param name="objEntry"></param>
		public void UpdateEntry(EntryInfo objEntry, int tabId)
		{
			_dataProvider.UpdateEntry(objEntry.ContestEntryId, objEntry.EntryName, objEntry.Description, objEntry.AuthorName, objEntry.SortOrder, objEntry.Active, objEntry.PermitVoting, objEntry.SmallImageUrl, objEntry.LargeImageUrl, objEntry.DemoUrl, objEntry.DownloadUrl, objEntry.ModuleId, objEntry.LastModifiedByUserId, objEntry.EnableDownload, objEntry.AuthorUrl, objEntry.Category, objEntry.ContentItemId);

			ClearCachedActiveEntries(objEntry.ModuleId);
		}

		/// <summary>
		/// Deletes an entry from the data store.
		/// </summary>
		/// <param name="itemId"></param>
		/// <param name="portalId"></param>
		public void DeleteEntry(int contestEntryId, int moduleid)
		{
			_dataProvider.DeleteEntry(contestEntryId, moduleid);
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="moduleId"></param>
		/// <returns></returns>
		public VoteInfo GetCachedVote(int userID, int moduleId, bool perDay)
		{
			var strCacheKey = "Contest-VoteCache" + "-" + moduleId + "-" + userID;
			var objVote = (VoteInfo)DataCache.GetCache(strCacheKey);

			if (objVote == null)
			{
				// caching settings
				var timeOut = 20 * Convert.ToInt32(DotNetNuke.Entities.Host.Host.PerformanceSetting);

				objVote = GetUserVote(userID, moduleId, perDay);

				//Cache Forum if timeout > 0 and Forum is not null
				if (timeOut > 0 & objVote != null)
				{
					DataCache.SetCache(strCacheKey, objVote, TimeSpan.FromMinutes(timeOut));
				}
			}
			return objVote;
		}

		/// <summary>
		/// Adds an item to the data store and returns the primary key that was generated for the new vote that was just added.
		/// </summary>
		/// <param name="objVote"></param>
		/// <returns></returns>
		public void AddVote(ref VoteInfo objVote)
		{
            objVote.ContestVoteID =_dataProvider.AddVote(objVote.ModuleID, objVote.ContestEntryID, objVote.UserID);
			ClearCache_Vote(objVote.UserID, objVote.ModuleID);
		}

		/// <summary>
		/// Updates an existing item in the data store.
		/// </summary>
		/// <param name="objVote"></param>
		public void UpdateVote(VoteInfo objVote)
		{
			_dataProvider.UpdateVote(objVote.ModuleID, objVote.ContestEntryID, objVote.UserID);
			ClearCache_Vote(objVote.UserID, objVote.ModuleID);
		}

		#endregion

		#region Private Methods

		/// <summary>
		/// Returns a collection of active contest entries for display (ie. multiple rows of data).
		/// </summary>
		/// <param name="moduleid"></param>
		/// <returns></returns>
		private List<EntryInfo> GetActiveEntries(int moduleid)
		{
			return CBO.FillCollection<EntryInfo>(_dataProvider.GetActiveEntries(moduleid));
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="moduleid"></param>
		private static void ClearCachedActiveEntries(int moduleid)
		{
			var strCacheKey = "Contest-Cache" + "-" + moduleid;

			DataCache.RemoveCache(strCacheKey);
		}

		/// <summary>
		/// returns a single User's Vote (equivalent to a single row of data)
		/// </summary>
		/// <param name="userID"></param>
		/// <param name="moduleID"></param>
		/// <returns></returns>
		private VoteInfo GetUserVote(int userID, int moduleID, bool perDay)
		{
			return (VoteInfo)CBO.FillObject(_dataProvider.GetUserVote(userID, moduleID, perDay), typeof(VoteInfo));
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="userID"></param>
		/// <param name="moduleId"></param>
		private void ClearCache_Vote(int userID, int moduleId)
		{
			var strCacheKey = "Contest-VoteCache" + "-" + moduleId + "-" + userID;
			DataCache.RemoveCache(strCacheKey);
		}

		// results
		public List<ResultsInfo> GetContestResults(int moduleId)
		{
			return CBO.FillCollection<ResultsInfo>(_dataProvider.GetContestResults(moduleId));
		}

		#endregion

		#region Private Methods

		/// <summary>
		/// This completes the things necessary for creating a content item in the data store. 
		/// </summary>
		/// <param name="objPost">The EntryInfo entity we just created in the data store.</param>
		/// <param name="tabId">The page we will associate with our content item.</param>
		/// <returns>The ContentItemId primary key created in the Core ContentItems table.</returns>
		private static int CompleteEntryCreation(EntryInfo objEntry, int tabId)
		{
			var cntTaxonomy = new Content();
			var objContentItem = cntTaxonomy.CreateContentItem(objEntry, tabId);

			return objContentItem.ContentItemId;
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="objPost"></param>
		/// <param name="tabId"></param>
		private static void CompleteEntryUpdate(EntryInfo objEntry, int tabId)
		{
			var cntTaxonomy = new Content();
			cntTaxonomy.UpdateContentItem(objEntry, tabId);

			// clear active entry cache and single item cache.
			ClearCachedActiveEntries(objEntry.ModuleId);
		}

		/// <summary>
		/// Cleanup any taxonomy related items.
		/// </summary>
		/// <param name="contentItemID"></param>
		private static void CompleteEntryDelete(int contentItemID)
		{
			var cntTaxonomy = new Content();
			cntTaxonomy.DeleteContentItem(contentItemID);
		}

		#endregion

	}
}